import { useState, useCallback, useEffect } from 'react';
import { type AxiosRequestConfig } from 'axios';
import { request } from '../utils/request';

import { type RequestOptions, type ApiError } from '../types/api';

interface UseApiResult<T> {
    data: T | null;
    loading: boolean;
    error: ApiError | null;
    run: (config?: AxiosRequestConfig, options?: RequestOptions<T>) => Promise<T>;
    refresh: () => Promise<T>;
    mutate: (data: T) => void;
    clear: () => void;
}

/**
 * 数据请求Hook
 */
export function useApi<T = any>(
    config: AxiosRequestConfig,
    options: RequestOptions<T> & { immediate?: boolean } = {}
): UseApiResult<T> {
    const [data, setData] = useState<T | null>(null);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState<ApiError | null>(null);
    const [currentConfig, setCurrentConfig] = useState(config);
    const [currentOptions, setCurrentOptions] = useState(options);

    const run = useCallback(async (
        newConfig?: AxiosRequestConfig,
        newOptions?: RequestOptions<T>
    ) => {
        const finalConfig = { ...currentConfig, ...newConfig };
        const finalOptions = { ...currentOptions, ...newOptions };

        setLoading(true);
        setError(null);

        try {
            const result = await request<T>(finalConfig, finalOptions);
            setData(result);
            setCurrentConfig(finalConfig);
            setCurrentOptions(finalOptions);
            return result;
        } catch (err) {
            setError(err as ApiError);
            throw err;
        } finally {
            setLoading(false);
        }
    }, [currentConfig, currentOptions]);

    const refresh = useCallback(() => run(), [run]);

    const mutate = useCallback((newData: T) => {
        setData(newData);
    }, []);

    const clear = useCallback(() => {
        setData(null);
        setError(null);
    }, []);

    // 立即执行
    useEffect(() => {
        if (options.immediate !== false) {
            run();
        }
    }, [run, options.immediate]);

    return {
        data,
        loading,
        error,
        run,
        refresh,
        mutate,
        clear,
    };
}